//------------------------------------------------------------------------------ 
//      Copyright (c) 2004-2009, Be Nanashi-San 
// 
//      Permission is hereby granted, free of charge, to any person obtaining a 
//      copy of this software and associated documentation files (the "Software"), 
//      to deal in the Software without restriction, including without limitation 
//      the rights to use, copy, modify, merge, publish, distribute, sublicense, 
//      and/or sell copies of the Software, and to permit persons to whom the 
//      Software is furnished to do so, subject to the following conditions: 
// 
//      The above copyright notice and this permission notice shall be included in 
//      all copies or substantial portions of the Software. 
// 
//      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
//      IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
//      FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
//      AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
//      LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
//      FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
//      DEALINGS IN THE SOFTWARE. 
// 
//      File Name:	Util.cpp
//      Author: 	Be Nanashi-San 
//      Description:	 
//------------------------------------------------------------------------------
#include "config.h"

#include <MenuItem.h>
#include <CheckBox.h>
#include <DataIO.h>
#include <Debug.h> // for PRINT()
#include <Directory.h>
#include <Entry.h>
#include <FindDirectory.h>
#include <Path.h>
#include <UTF8.h>
#include <stdio.h>
#include <string.h>
#include <String.h>
#include <Button.h>
#include <RadioButton.h>
#include <Roster.h>

#include "setting.h"
#include "Util.h"

////////////////////////////////////////////////////////////////////////////////
// MakeButton
//
// 20060814:移動
////////////////////////////////////////////////////////////////////////////////
BButton*
MakeButton(BRect r, const char *label, uint32 command, BView *view, bool b )
{
	BButton* aButton = new BButton(r, "", label, new BMessage(command), B_FOLLOW_RIGHT|B_FOLLOW_BOTTOM);
	aButton->SetEnabled(b);
	view->AddChild(aButton);
	return aButton;
}
////////////////////////////////////////////////////////////////////////////////
// MakeRadioButton
//
// 20060814:移動
////////////////////////////////////////////////////////////////////////////////
BRadioButton *
MakeRadioButton(BRect r,  const char *name, const char *label, uint32 command, BView *view)
{
	BRadioButton* rb = new BRadioButton(r, name, label, new BMessage(command));
	view->AddChild(rb);
	return rb;
}
////////////////////////////////////////////////////////////////////////////////
// MakeCheckBox
//
// 
////////////////////////////////////////////////////////////////////////////////
BCheckBox *
MakeCheckBox(BRect r,  const char *name, const char *label, uint32 command, BView *view)
{
	BCheckBox* cb = new BCheckBox(r, name, label, new BMessage(command));
	view->AddChild(cb);
	return cb;
}
////////////////////////////////////////////////////////////////////////////////
// MakeItem
// メニューアイテム作成。
// 20051113:関数として抽出。
////////////////////////////////////////////////////////////////////////////////
BMenuItem *
MakeItem(BHandler *target, const char * label, uint32 command, char shortcut, uint32 modifiers)
{
	BMenuItem *item = new BMenuItem(label, new BMessage(command), shortcut, modifiers);
	item->SetTarget(target);
	return item;
}

BMenuItem *
MakeItem(BHandler *target, const char * label, uint32 command, const char *text)
{
	BMessage *m = new BMessage(command);
	m->AddString("text", text);
	BMenuItem *item = new BMenuItem(label, m);
	item->SetTarget(target);
	return item;
}
BMenuItem *
MakeItem(BHandler *target, const char * label, uint32 command, BString &text)
{
	return MakeItem(target, label, command, text.String());
}
////////////////////////////////////////////////////////////////////////////////
// ClearCache
// 指定スレのCacheをごみ箱に移動。
//
////////////////////////////////////////////////////////////////////////////////
static status_t
GotoTrash(BEntry &ent)
{
	if(ent.InitCheck() != B_OK){
		return B_ERROR;
	}
		
	// ごみ箱へのパスを求める。
	BPath trashPath;
	if(find_directory (B_TRASH_DIRECTORY, &trashPath) != B_OK){
		return B_ERROR;
	}
	
	// ごみ箱ディレクトリオブジェクトを作成。
	BDirectory trashDir(trashPath.Path());
	if(trashDir.InitCheck() != B_OK){
		return B_ERROR;
	}
	
	// ごみ箱へ移動。
	if(ent.MoveTo(&trashDir) != B_OK){
		return B_ERROR;
	}

	return B_OK;
}
////////////////////////////////////////////////////////////////////////////////
// ClearAllCache
// 2chCacheの内容を全てごみ箱に移動。
//
////////////////////////////////////////////////////////////////////////////////
void
ClearBBSCache()
{
	BDirectory dir;
	findcachedir(&dir, kCACHE_DIR_NAME);
	
	BEntry ent(&dir, NULL);
	if(GotoTrash(ent) != B_OK) return;
	
	//TODO:現在表示されているスレ一覧の更新。
}
////////////////////////////////////////////////////////////////////////////////
// void findcachedir
// 各種ファイルのあるディレクトリを返す。
////////////////////////////////////////////////////////////////////////////////
void
findcachedir(BDirectory *cachedir, const char *dir, const char *uri/* = NULL*/)
{
	BString user_setting_path(kSETTING_PATH);

	user_setting_path << dir;
	if(uri){
		user_setting_path << '/' << uri;
	}
	
	BEntry ent(user_setting_path.String());
	if(ent.Exists() == false){
		create_directory(user_setting_path.String(), 0777);	//0777は8進数
	}
	cachedir->SetTo(user_setting_path.String());
}
////////////////////////////////////////////////////////////////////////////////
// cutf8
// SJISストリームからutf8に変換。
// Zeta 2スレのBe名無しさん@619 作。
////////////////////////////////////////////////////////////////////////////////
void
cutf8(BPositionIO *in, BPositionIO *out)
{
	const int32 C_BUFFER_SIZE = 4096;
	status_t state = B_OK;
	char data[C_BUFFER_SIZE];
	int32 left = 0, cookie = 0, effect = C_BUFFER_SIZE / 2, center = C_BUFFER_SIZE / 2;
	
	while (effect) {
		char *src = data + center;
		char *dst = data;
		effect = left + in->Read(src + left, C_BUFFER_SIZE - center - left);
		if (effect) {
			int32 srcLen = effect;
			int32 dstLen = center;
			state = convert_to_utf8(B_SJIS_CONVERSION, src, &srcLen, dst, &dstLen, &cookie);
			PRINT(("cutf8(%ld(%ld)|%ld(%ld)) ", dstLen, center - dstLen, srcLen, effect - srcLen));

			int32 s = 0;	/* 文字列の途中にヌル文字があったら Write()しない */
			dst[dstLen] = '\0';
			while (s < dstLen)
				if (dst[s] == '\0')
					s++;
				else {
					int32 length = strlen(dst + s);
					out->Write(dst + s, length);
					s += length;
				}

			//107 ：Be名無しさん ：2006/04/08(土) 14:32:26
			//    >>2ch+
			//    2ch+で使われているcutf8においてhaiku-osのlibtextencoding.soを使って
			//    いると正しく変換できない場合があることが判明しました。
			//    cutf8は変換する際に何回かに分割して変換します。しかし分割する際、
			//    コードの判定をしないのでSJISコードの途中で分割する可能性があります。
			//    haiku-osのlibtextencoding.soではこれをゴミコードだとして捨てて
			//    しまいます。そのため残ったコードが正しくないコードに変換されてしまいます。
			int32 diff = (center - dstLen) - (effect - srcLen);
			if (64 < ABS(diff)){
				center -= diff / 2;
				PRINT(("%ld ", center));
				PRINT(("\n"));
			}

			left = effect - srcLen;
			if (0 < left) memcpy(data + center, src + srcLen, left);
		}
	}
}
////////////////////////////////////////////////////////////////////////////////
// Launcher
//
//
////////////////////////////////////////////////////////////////////////////////
void
Launcher(const char *type, const char *param)
{
	char *argv = strdup(param);
	be_roster->Launch(type, 1, &argv);
	free(argv);
}
